﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TGPInterfaceParam;
using PSE.Framework.Communication.Adapters.Tgp;
using System.Xml;
using System.Xml.Linq;
using System.Threading;

namespace PSE.Framework.Communication.Adapters.Tgp
{
    /// <summary>
    /// Classe com métodos comuns entre os adapters TGP
    /// </summary>
    internal class TgpCommon
    {
        #region Construtor
        private TGPExecutorNet.TGPExecutor _tgpExecutor;
        private TgpOpenParameter _openParameter;
        private int _authenticationRetry;
        private int _authenticationRetryWait;

        /// <summary>
        /// Construtor padrão
        /// </summary>
        /// <param name="tgpExecutor">Instância do TGP executor</param>
        /// <param name="openParameter">Parâmetro de abertura</param>
        /// <param name="authenticationRetry">
        /// Número de vezes que deve tentar capturar a resposta da autenticação
        /// </param>
        /// <param name="authenticationRetryWait">
        /// Tempo de espera em milisegundos que deve aguardar antes de tentar capturar a resposta da autenticação
        /// </param>
        public TgpCommon(TGPExecutorNet.TGPExecutor tgpExecutor, 
                         TgpOpenParameter openParameter,
                         int authenticationRetry,
                         int authenticationRetryWait)
        {
            _tgpExecutor = tgpExecutor;
            _openParameter = openParameter;
            _authenticationRetry = authenticationRetry;
            _authenticationRetryWait = authenticationRetryWait;
        }
        #endregion

        #region Open
        /// <summary>
        /// Abre a comunicação com o TGP e faz a autenticação
        /// </summary>
        public void Open()
        {
            _tgpExecutor.InicioProcessoMensagem(_openParameter.InstituicaoOrigem, _openParameter.InstituicaoDestino, _openParameter.Usuario, _openParameter.Sistema);

            this.Authenticate();
        }
        #endregion

        #region Close
        /// <summary>
        /// Fecha a comunicação com o TGP
        /// </summary>
        public void Close()
        {
            _tgpExecutor.FimProcessoMensagem(_openParameter.InstituicaoOrigem, _openParameter.InstituicaoDestino, _openParameter.Usuario, _openParameter.Sistema);
        }
        #endregion

        #region Authenticate
        /// <summary>
        /// Autentica no TGP
        /// </summary>
        private void Authenticate()
        {
            ParametroEntrada parametroEntrada = new ParametroEntrada();
            ParametroSaida parametroSaida = new ParametroSaida();
            //string sXml;
            string usr = _openParameter.InstituicaoOrigem + ":" + _openParameter.Usuario;
            string pwd = _openParameter.Senha;
            string sis = _openParameter.Sistema;

            XDocument doc = new XDocument(
                new XElement("CASAutentica",
                    new XElement("CodMsg", "CAS0001"),
                    new XElement("AUTHCAS",
                        new XElement("USUARIO", usr),
                        new XElement("SENHA", pwd),
                        new XElement("SENHAEXPIRADA", "FALSE"),
                        new XElement("NOVASENHA", null),
                        new XElement("SISTEMA", sis),
                        new XElement("PVS", null)
                    ),
                    new XElement("DtHrPart", DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss"))
                )
            );
            
            //sXml = "<CASAutentica>" + Environment.NewLine;
            //sXml = sXml + "\t<CodMsg>CAS0001</CodMsg>" + Environment.NewLine;
            //sXml = sXml + "\t<AUTHCAS>" + Environment.NewLine;
            //sXml = sXml + "\t\t<USUARIO>" + usr + "</USUARIO>" + Environment.NewLine;
            //sXml = sXml + "\t\t<SENHA>" + pwd + "</SENHA>" + Environment.NewLine;
            //sXml = sXml + "\t\t<SENHAEXPIRADA>FALSE</SENHAEXPIRADA>" + Environment.NewLine;
            //sXml = sXml + "\t\t<NOVASENHA></NOVASENHA>" + Environment.NewLine;
            //sXml = sXml + "\t\t<SISTEMA>" + sis + "</SISTEMA>" + Environment.NewLine;
            //sXml = sXml + "\t\t<PVS></PVS>" + Environment.NewLine;
            //sXml = sXml + "\t</AUTHCAS>" + Environment.NewLine;
            //sXml = sXml + "\t<DtHrPart>" + DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss") + "</DtHrPart>" + Environment.NewLine;
            //sXml = sXml + "</CASAutentica>";

            parametroEntrada.InstituicaoOrigem = _openParameter.InstituicaoOrigem;
            parametroEntrada.InstituicaoDestino = _openParameter.InstituicaoDestino;
            parametroEntrada.Usuario = _openParameter.Usuario;
            parametroEntrada.Sistema = _openParameter.Sistema;
            parametroEntrada.TipoComando = TGPInterfaceParam.TipoComando.TCPutMsg;
            parametroEntrada.TipoMensagem = (TGPInterfaceParam.TipoMensagem)TipoMensagem.TMAutentica;
            parametroEntrada.Mensagem = doc.ToString(); //sXml;

            // Enviando mensagem de autenticação
            _tgpExecutor.Executa(parametroEntrada, out parametroSaida);
            

            parametroEntrada.TipoComando = TGPInterfaceParam.TipoComando.TCGetMsg;
            parametroEntrada.TipoMensagem = (TGPInterfaceParam.TipoMensagem)TipoMensagem.TMRespAutentica;

            int retryCount = 1;

            // Capturando resposta da autenticação, se não for retornada nehuma resposta aguarda o 
            // tempo especificado e tenta capturar novamente até atingir o limite

            while (true)
            {
                _tgpExecutor.Executa(parametroEntrada, out parametroSaida);

                if (parametroSaida.ColRespMensagem.Count > 0)
                {
                    break;
                }
                else if (retryCount <= _authenticationRetry)
                {
                    retryCount++;
                    Thread.Sleep(_authenticationRetryWait);
                }
                else
                {
                    throw new System.Security.Authentication.AuthenticationException("Cannot get TGP authentication response, ColRespMensagem is empty");
                }
            }

            RespMensagem resp = parametroSaida.ColRespMensagem[0];
            

            //extrair da mensagem retorna a informacao que indica se a autenticacao foi ou nao realizada com sucesso
            XmlDocument d = new XmlDocument();
            d.LoadXml(resp.Mensagem);
            XmlNode node = d.SelectSingleNode("/CASAutenticaResp/CASRET/MSG");

            if (!string.IsNullOrEmpty(node.InnerText))
                throw new System.Security.Authentication.AuthenticationException(string.Format("TGP authentication fail: {0}", node.InnerText));
        }
        #endregion

        #region SendEchoMessage
        /// <summary>
        /// Envia mensagem de eco
        /// </summary>
        /// <returns>Código da mensagem</returns>
        public int SendEchoMessage()
        {
            return _tgpExecutor.EnviaECO();
        }
        #endregion

        #region GetEchoMessageStatus
        /// <summary>
        /// Captura o status da mensagem de eco
        /// </summary>
        /// <param name="codigoMensagem">Código da mensagem</param>
        /// <returns>Status da mensagem</returns>
        public TgpMessageStatus GetEchoMessageStatus(int codigoMensagem)
        {
            if (codigoMensagem <= 0)
                throw new ArgumentOutOfRangeException("codigoMensagem");

            int iRetorno = _tgpExecutor.ConsultaECO(codigoMensagem);

            if (Enum.IsDefined(typeof(TgpMessageStatus), iRetorno))
                return (TgpMessageStatus)iRetorno;
            else
                return TgpMessageStatus.Indefinido;
        }
        #endregion
    }
}
